#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@File   : test05_user_management.py
@Time : 2025/2/5 15:57
@Author: Wangwc
@Describe:  ……
"""
import random
import warnings

from urllib3.exceptions import InsecureRequestWarning

warnings.filterwarnings("ignore", category=InsecureRequestWarning)

import time
import allure
import pytest

from business.UserApi import UserApi
# from business.SystemApi import SystemApi
from utils.login import Login
from commons.logger import log
from utils.config_tools import Config
from commons.fake_data import Fake

# TODO 当前模块的配置文件名称，配置在config目录下
config_name = "user.ini"
login = Login(config_name=config_name)
config = Config(config_name=config_name)
# 默认使用管理员账号登录，如果想切换账号，也可以使用 login = Login(user='user2',config_name=config_name)

# TODO 用户名暂时所有测试用例统一，因为后面的测试用例需要使用
username = Fake.generate_english_username()
raw_passwd = Fake.generate_password()

# TODO 通过链接邀请创建用户的账号、密码
new_username = Fake.generate_english_username()
new_raw_passwd = Fake.generate_password()

# TODO 新增用户组名称
group_name = Fake.generate_english_username()

# 全局变量存储 token
global_token = None


def get_token():
    global global_token
    if global_token is None:
        global_token = login.login()
    return global_token


@pytest.fixture(scope="function")
def init_api():
    """
    用于初始化UserApi客户端的夹具
    """
    token = get_token()
    api = UserApi(token, configname=config_name)
    return api

#
# @pytest.fixture(scope="function")
# def system_api():
#     """
#     用于初始化SystemApi客户端的夹具
#     """
#     token = get_token()
#     api = SystemApi(token, configname=config_name)
#     return api


#研究一下这个函数

def handle_api_call(api_method, *args, attach_to_allure=True, format_result=None, **kwargs):
    if not callable(api_method):
        raise TypeError("api_method 参数必须是可调用对象（如函数或方法）")
    if attach_to_allure is not None and not isinstance(attach_to_allure, bool):
        raise TypeError("attach_to_allure 参数必须是布尔类型或者为 None")
    if format_result is not None and not callable(format_result):
        raise TypeError("format_result 参数必须是可调用对象（如函数）或者为 None")

    max_retries = 3
    for retry in range(max_retries):
        try:
            result = api_method(*args, **kwargs)
            if attach_to_allure:
                if format_result:
                    formatted_result = format_result(result)
                else:
                    formatted_result = str(result)
                allure.attach(formatted_result, f"{api_method.__name__} 调用结果", allure.attachment_type.TEXT)
            log.info(f"{api_method.__name__} 调用成功")
            return result
        except Exception as e:
            allure.attach(str(e), f"{api_method.__name__} 调用错误信息", allure.attachment_type.TEXT)
            log.error(f"{api_method.__name__} 调用出现错误: {e}", exc_info=True)
            # 假设根据错误信息判断 token 过期
            if "token 过期" in str(e) and retry < max_retries - 1:
                global global_token
                global_token = login.login()
                api_method.__self__.token = global_token
                continue
            elif isinstance(e, ConnectionError):
                log.error("连接错误，可能是网络问题，请检查网络连接。")
            elif isinstance(e, ValueError):
                log.error("值错误，可能是传入的参数有误，请检查参数。")
            raise


@allure.feature("控制面板-用户管理")
class TestUserManagement():
    @allure.title("创建单个用户")
    def test_create_user(self, init_api):
        with allure.step("获取当前用户列表信息"):
            user_list = handle_api_call(init_api.get_user_list)

        with allure.step("构造用户密码数据"):
            rsa_token = login.verify_check()
            log.info(f"获取到的ras_token为：{rsa_token}")
            password = login.data_encrypt.rsa_passwd(rsa_token, raw_passwd)
            log.info(f"加密后的密码为：{password}")

        with allure.step("用户密码规则"):
            handle_api_call(init_api.user_rule_password, username, password)
            time.sleep(0.5)

        with allure.step("创建用户"):
            handle_api_call(init_api.create_user, username, password)
            log.debug(f"这里在开始创建用户，用户名：{username}")
            time.sleep(0.5)

        with allure.step("校验用户成功创建"):
            new_user_list = handle_api_call(init_api.get_user_list)
            assert len(new_user_list) == len(user_list) + 1, "创建用户后，用户列表长度应该增加1"

    @allure.title("搜索用户")
    def test_search_user(self, init_api):
        with allure.step("获取当前用户列表信息"):
            user_list = handle_api_call(init_api.get_user_list)

        with allure.step("搜索结果为空"):
            empty_search = handle_api_call(init_api.search_user, "")
            assert len(empty_search) == len(user_list), f"搜索结果为空时，应该返回所有用户，实际返回用户为：{empty_search}"

        with allure.step("精确搜索"):
            exact_search = handle_api_call(init_api.search_user, username)
            assert len(exact_search) == 1, "精确搜索时，应该返回1个用户"

        with allure.step("模糊搜索"):
            vague_search = handle_api_call(init_api.search_user, "t")
            assert len(vague_search) <= len(user_list), "模糊搜索时，应该返回多个用户"

        with (allure.step("错误搜索")):
            error_search = handle_api_call(init_api.search_user, "tackeojdk")
            assert len(error_search) == 0,f"错误搜索时，应该返回0个用户,实际返回用户为：{error_search}"

        with allure.step("通配符搜索"):
            wild_card_search = handle_api_call(init_api.search_user, "%")
            assert len(wild_card_search) == 0, f"通配符搜索时，应该返回0个用户,实际返回用户为：{wild_card_search}"

    @allure.title("给用户设置共享文件夹权限")
    def test_set_user_permission(self, init_api):
        with allure.step("获取当前用户uid信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, username)

        with allure.step("获取当前用户共享文件夹权限"):
            permission_list = handle_api_call(init_api.get_user_permission, uid)

        with allure.step("设置当前用户共享文件夹权限"):
            path = permission_list[0].get('path')
            permission = permission_list[0].get('permission')
            if permission == -1:
                set_permission = 5
            elif permission == 5:
                set_permission = 7
            else:
                set_permission = -1
            path_list = [{"path": path, "permission": set_permission}]
            handle_api_call(init_api.set_user_permission, uid, path_list)

        with allure.step("再次获取前用户共享文件夹权限"):
            new_permission_list = handle_api_call(init_api.get_user_permission, uid)
            assert new_permission_list[0].get('permission') == set_permission, "设置共享文件夹权限失败"

    @allure.title("对用户文件夹进行限额")
    def test_set_user_folder(self, init_api):
        with allure.step("获取当前用户uid信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, username)

        with allure.step("获取当前用户文件夹限额信息"):
            user_info = handle_api_call(init_api.get_user_information, uid)
            dir_quota = user_info.get('dir_quota')

        with allure.step("给用户文件夹设置限额"):
            handle_api_call(init_api.edit_user, username, uid, dir_quota=50)
            log.debug(f"这里在更改用户：{username}")
            time.sleep(3)

        with allure.step("再次获取当前用户文件夹限额信息"):
            new_user_info = handle_api_call(init_api.get_user_information, uid)
            assert new_user_info.get('dir_quota') == 50, "设置用户文件夹限额失败"

    @allure.title("更改用户管理员权限")
    def test_set_user_role(self, init_api):
        with allure.step("获取当前用户uid信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, username)

        with allure.step("获取当前用户角色信息"):
            user_info = handle_api_call(init_api.get_user_information, uid)
            role = user_info.get('role')

        with allure.step("修改用户角色"):
            if role == 'admin':
                set_role = 'users'
            else:
                set_role = 'admin'
            handle_api_call(init_api.edit_user, username, uid, role=set_role, dir_quota=20)
            log.debug(f"这里在更改用户角色：{username}")
            time.sleep(3)

        with allure.step("再次获取用户角色信息"):
            new_user_info = handle_api_call(init_api.get_user_information, uid)
            assert new_user_info.get('role') == set_role, "设置用户文件夹限额失败"

    @allure.title("编辑用户信息")
    def test_edit_user_informaition(self, init_api):
        with allure.step("获取当前用户uid信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, username)

        with allure.step("根据用户uid获取当前用户信息"):
            user_info = handle_api_call(init_api.get_user_information, uid)

        with allure.step("编辑用户信息"):
            handle_api_call(init_api.edit_user, username, uid, email='test@163.com', description='这个是我添加的描述内容')
            log.debug(f"这里在更改用户信息：{username}")
            time.sleep(3)

        with allure.step("再次获取用户信息"):
            new_user_info = handle_api_call(init_api.get_user_information, uid)
            assert new_user_info != user_info, "设置用户文件夹限额失败"

    @allure.title("更换其他用户头像")
    def test_change_user_headpic(self, init_api):
        with allure.step("获取当前用户uid信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, username)

        with allure.step("获取默认头像列表"):
            headpic_list = handle_api_call(init_api.get_user_headpic_list)
            set_headpic = headpic_list[random.randint(1, 20)]
            result = handle_api_call(init_api.get_headpic_stream, set_headpic)
            set_content = result.content

        with allure.step("更换用户头像"):
            handle_api_call(init_api.change_user_headpic, uid, icon=set_headpic)
            time.sleep(5)

        with allure.step("再次获取用户头像信息"):
            new_headpic = handle_api_call(init_api.get_user_headpic, uid)
            new_content = new_headpic.content
            assert new_content == set_content, f"更换头像失败，预期头像：{set_content}，实际头像：{new_headpic}"

    @allure.title("更换其他用户密码")
    def test_change_other_user_password(self, init_api):
        with allure.step("创建新用户"):
            new_name = Fake.generate_english_username()
            raw_passwd = Fake.generate_password()
            Ras_Token = login.verify_check()
            passwd = login.data_encrypt.rsa_passwd(Ras_Token, raw_passwd)
            log.debug(f"这里在创建用户，用户名：{new_name}")
            handle_api_call(init_api.create_user, new_name, passwd)
            uid = handle_api_call(init_api.get_user_uid_by_username, new_name)

        with allure.step("密码处理"):
            Ras_Token = login.verify_check()
            set_raw_password = Fake.generate_password()
            set_password = login.data_encrypt.rsa_passwd(Ras_Token, set_raw_password)

        with allure.step("更换用户密码(编辑用户密码）"):
            handle_api_call(init_api.edit_user, new_name, uid, password=set_password)
            log.debug(f"这里在更改用户密码：{new_name}")
            time.sleep(1)

        with allure.step("使用新密码登录"):
            new_rsa_token = login.verify_check(username=new_name)
            new_password = login.data_encrypt.rsa_passwd(new_rsa_token, set_raw_password)
            token = login.login(username=new_name, password=new_password)
            assert token != None, "更换密码后，登录失败"

        with allure.step("删除用户"):
            Ras_Token = login.verify_check()
            password = config.read_config_ini('user', 'user_pwd')
            x_curpass_token = login.data_encrypt.rsa_passwd(Ras_Token, password)
            handle_api_call(init_api.delete_user, uid,x_curpass_token)
            log.debug(f"这里在第1次删除用户")
            time.sleep(1)

    @allure.title("查看存储配额信息")
    def test_check_user_directory_quota(self, init_api):
        with allure.step("获取当前用户uid信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, username)

        with allure.step("设置用户存储配额"):
            dir_quota = random.randint(30, 300)
            handle_api_call(init_api.edit_user, username, uid, dir_quota=dir_quota, unit=0)
            log.debug(f"这里在更改用户存储配额:{username}")
            time.sleep(1)

        with allure.step("使用新创建的用户登录"):
            rsa_token = login.verify_check(username=username)
            password = login.data_encrypt.rsa_passwd(rsa_token, raw_passwd)
            token = login.login(username=username, password=password)
            assert token != None, "更换密码后，登录失败"

        with allure.step("获取用户存储配额"):
            user = UserApi(token)
            quota_info = user.get_user_directory_quota()
            quota = quota_info.get('dir_quota')
            assert quota == dir_quota * 1024 * 1024, f"用户存储配额设置失败，预期{dir_quota * 1024 * 1024}字节，实际{quota}字节"

    @allure.title("删除用户信息")
    def test_delete_user(self, init_api):
        with allure.step("获取当前用户列表信息"):
            user_list = handle_api_call(init_api.get_user_list)

        with allure.step("获取当前用户uid信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, username)

        with allure.step("删除用户信息"):
            rsa_token = login.verify_check()
            raw_passwd = config.read_config_ini('user', 'user_pwd')
            x_curpass_token = login.data_encrypt.rsa_passwd(rsa_token, raw_passwd)
            handle_api_call(init_api.delete_user, uid, x_curpass_token)
            log.debug(f"这里在第2次删除用户")

        with allure.step("再次获取当前用户列表信息"):
            new_user_list = handle_api_call(init_api.get_user_list)
            assert len(new_user_list) == len(user_list) - 1, "删除用户后，用户列表长度应该减少1"

    @allure.title("通过链接邀请创建用户")
    def test_invite_user(self, init_api):
        with allure.step("获取邀请码"):
            my_username = config.read_config_ini('user', 'user_name')
            uid = handle_api_call(init_api.get_user_uid_by_username, my_username)
            invite_code = handle_api_call(init_api.get_invite_state, uid)

        with allure.step("获取uglink信息"):
            result = handle_api_call(init_api.get_uglink_status)
            internalDomain = result.get('internalDomain')

        with allure.step("校验用户名信息"):
            data = handle_api_call(init_api.check_username, internalDomain, invite_code, new_username)
            assert data == {}, f'用户名{new_username}已存在'

        with allure.step("获取当前用户rsatoken"):
            ras_token = handle_api_call(init_api.get_invite_rsatoken, internalDomain, my_username)
            new_passwd = login.data_encrypt.rsa_passwd(ras_token, new_raw_passwd)

        with allure.step("申请创建用户"):
            invite_list = handle_api_call(init_api.get_user_invite_list)
            handle_api_call(init_api.user_invite, internalDomain, invite_code, new_username, new_passwd, email='',
                            reason='测试一下')
            time.sleep(1)
            new_invite_list = handle_api_call(init_api.get_user_invite_list)
            assert len(new_invite_list) == len(invite_list) + 1, "邀请用户后，邀请列表长度应该增加1"

    @allure.title("审批链接创建的用户")
    def test_agree_user(self, init_api):
        with allure.step("获取申请列表信息"):
            invite_list = handle_api_call(init_api.get_user_invite_list)
            id = invite_list[0].get('ID')

        with allure.step("审批用户"):
            agree_list = handle_api_call(init_api.get_agree_user_list)
            handle_api_call(init_api.agree_invite, id, role='admin')
            time.sleep(1)

        with allure.step('确认审批信息'):
            new_invite_list = handle_api_call(init_api.get_user_invite_list)
            new_agree_list = handle_api_call(init_api.get_agree_user_list)
            assert len(new_invite_list) == len(invite_list) - 1, "审批用户后，邀请列表长度应该减少1"
            assert len(new_agree_list) == len(agree_list) + 1, "审批用户后，审批列表长度应该增加1"

    @allure.title("使用审批后的新用户登录并删除用户")
    def test_login_and_delete_user(self, init_api):
        with allure.step("使用新用户获取rsa_token"):
            rsa_token = login.verify_check(new_username)
            new_passwd = login.data_encrypt.rsa_passwd(rsa_token, new_raw_passwd)

        with allure.step("使用新用户登录"):
            result = login.login(new_username, new_passwd)
            assert result != None, "新用户登录失败"

        with allure.step("删除用户信息"):
            uid = handle_api_call(init_api.get_user_uid_by_username, new_username)
            rsa_token = login.verify_check()
            raw_passwd = config.read_config_ini('user', 'user_pwd')
            x_curpass_token = login.data_encrypt.rsa_passwd(rsa_token, raw_passwd)
            handle_api_call(init_api.delete_user, uid, x_curpass_token)
            log.debug(f"这里在第3次删除用户")

    @allure.title("新增用户组")
    def test_add_user_group(self, init_api):
        with allure.step("获取当前用户组列表"):
            user_group_list = handle_api_call(init_api.get_user_group_list)

        with allure.step("新增用户组"):
            handle_api_call(init_api.create_user_group, group_name)
            time.sleep(1)

        with allure.step("再次获取当前用户组列表"):
            new_user_group_list = handle_api_call(init_api.get_user_group_list)
            assert len(new_user_group_list) == len(user_group_list) + 1, "新增用户组后，用户组列表长度应该增加1"

    @allure.title("搜索用户组")
    def test_search_group(self, init_api):
        with allure.step("获取当前用户组列表信息"):
            user_list = handle_api_call(init_api.get_user_group_list)

        with allure.step("精确搜索"):
            exact_search = handle_api_call(init_api.search_user_group, group_name)
            assert len(exact_search) == 1, "精确搜索时，应该返回1个用户组"

        with allure.step("模糊搜索"):
            vague_search = handle_api_call(init_api.search_user_group, group_name[1:])
            assert len(vague_search) <= len(user_list), "模糊搜索时，应该返回多个用户组"

        with allure.step("错误搜索"):
            error_search = handle_api_call(init_api.search_user_group, "tackeojdk")
            assert len(error_search) == 1, f"错误搜索时，应该返回0个用户组,实际返回用户组为：{error_search}"

        with allure.step("通配符搜索"):
            wild_card_search = handle_api_call(init_api.search_user_group, "%")
            assert len(wild_card_search) == 1, f"通配符搜索时，应该返回0个用户,实际返回用户组为：{wild_card_search}"

    @allure.title("给用户组设置共享文件夹权限")
    def test_set_user_group_permission(self, init_api):
        with allure.step("获取当前用户组gid信息"):
            gid = handle_api_call(init_api.get_gid_by_groupname, group_name)

        with allure.step("获取当前用户共享文件夹权限"):
            permission_list = handle_api_call(init_api.get_group_permission_by_id, gid)

        with allure.step("设置当前用户共享文件夹权限"):
            path_list = []
            for i, item in enumerate(permission_list):
                path = item.get('path')
                permission = item.get('permission')
                if permission == -1:
                    set_permission = 5
                elif permission == 5:
                    set_permission = 7
                else:
                    set_permission = -1
                path_list.append({"path": path, "permission": set_permission})
            handle_api_call(init_api.set_group_permission, gid, path_list)
            time.sleep(1)

        with allure.step("再次获取当前用户共享文件夹权限"):
            new_permission_list = handle_api_call(init_api.get_group_permission_by_id, gid)
            # 检查修改的元素权限是否正确更新
            new_path_list = [{"path": item.get('path'), "permission": item.get('permission')} for item in
                             new_permission_list]
            assert new_path_list == path_list, f"给用户组设置共享文件夹权限失败，预期结果为{path_list}，实际结果为{new_path_list}"

    @allure.title("修改用户组成员")
    def test_change_user_group(self, init_api):
        # 步骤一：获取当前用户组成员
        with allure.step("获取当前用户组成员数"):
            try:
                gid = handle_api_call(init_api.get_gid_by_groupname, group_name)
                group_info = handle_api_call(init_api.get_group_info_by_gid, gid)
                old_users = group_info.get('users')
                log.info(f"修改前用户组中的用户列表: {old_users}")
            except Exception as e:
                log.error(f"获取当前用户组成员信息时出错: {e}")
                raise

        # 步骤二：修改用户组成员
        with allure.step("修改用户组成员"):
            try:
                username_list = handle_api_call(init_api.get_user_name_list)
                # 修正 users 数据结构
                users = [{"name": username} for username in username_list]
                handle_api_call(init_api.edit_user_group, group_name, gid, users=users, description='修改用户组成员')
                time.sleep(1)
                log.info(f"尝试将以下用户添加到用户组: {[user['name'] for user in users]}")
            except Exception as e:
                log.error(f"修改用户组成员时出错: {e}")
                raise

        # 步骤三：再次获取当前用户组成员
        with allure.step("再次获取当前用户组成员数"):
            try:
                new_group_info = handle_api_call(init_api.get_group_info_by_gid, gid)
                new_users_list = new_group_info.get('users')
                new_users = [{"username": user['name']} for user in new_users_list]
                new_users_volues = sorted([user['username'] for user in new_users])
                users_volues = sorted([user['name'] for user in users])
                assert new_users_volues == users_volues, "修改用户组成员后，用户组中的用户列表应该与修改后的用户列表一致"
            except Exception as e:
                log.error(f"再次获取用户组成员信息时出错: {e}")
                raise

    @allure.title("删除用户组")
    def test_delete_user_group(self, init_api):
        with allure.step("获取当前用户组列表"):
            user_group_list = handle_api_call(init_api.get_user_group_list)

        with allure.step("删除用户组"):
            gid = handle_api_call(init_api.get_gid_by_groupname, group_name)
            handle_api_call(init_api.delete_user_group, gid)
            time.sleep(0.5)

        with allure.step("再次获取当前用户组列表"):
            new_user_group_list = handle_api_call(init_api.get_user_group_list)
            assert len(new_user_group_list) == len(user_group_list) - 1, "删除用户组后，用户组列表长度应该减少1"


